package com.evolved.automata.android.bots.speechbot;
import com.evolved.automata.*;
import java.util.*;

public class SpeechProcessor 
{
	public static final String wordValueToken="W";
	
	
	InferenceController j_Controller;

	static final String spokenWordKeyName="original_word";
	
	static final String substitutedWordKeyName="substituted_word";
	
	static final String parametersRequiredP = "argsP";

	static final KeyValuePair kvSubstitutionOnlyFilter = new KeyValuePair("replacementmapP", "T");
	
	static final KeyValuePair kvFunctionNamesOnlyFilter = new KeyValuePair("definitionP", "T");
	
	static final String functionSetKeyName = "function";
	
	float tolerance=.00001F;
	
	public static class SpeechResults
	{
		String[] arguments;
		String functionName;
		String rawWords;
		public SpeechResults(String fName,String[] parameters,String raw )
		{
			arguments=parameters;
			functionName=fName;
			rawWords=raw;
		}
	}
	
	
	/**
	 * 
	 * @param controller: This is the controller that encapsulates the StructureModels
	 * @param speechFilterKeyValuePair: This is the key-value pair that filters all slices that pertain to speech processing
	 * @param functionSelectKey: this is the key name whose values specify a speech processing function
	 * @param speechMapFilterKeyValuePair: This is the filter key value pair for the synonym map
	 * @param spokenWordKey: This is the key for the words spoken by the user
	 * @param mappedValueKey: This is a key for the value to replace it with
	 */
	public SpeechProcessor(InferenceController controller)
	{
		j_Controller=controller;
		
		
	}
	
	public SpeechResults[] processSpeech(String rawSpeech)
	{
		String[] words = StandardTools.splitCommaDelimitedString(rawSpeech, ' ');

		Hashtable<String,String> parameterMap = new Hashtable<String,String>(), workingMap;
		for (int i=0;i<words.length;i++)
		{
			parameterMap.put(words[i].toLowerCase(), wordValueToken);
			
		}
		
		parameterMap.put(kvFunctionNamesOnlyFilter.GetKey(), kvFunctionNamesOnlyFilter.GetValue());
		
		String[] worlds = j_Controller.getAllConsistentWorlds(parameterMap,false);
		
		Hashtable<String,String> consistentWorld, substitutionMap;
		String functionName;
		String newWord;
		boolean first=true;
		float canonicalWordCount=0, wordsPresentCount=0, maxFraction=0, extraWords=0, currentFraction;
		Hashtable<String,SpeechResults> applicableFunctions = new Hashtable<String, SpeechProcessor.SpeechResults>();
		LinkedList<String> functionArguments = new LinkedList<String>();
		boolean requiresArgumentsP;
		for (String world:worlds)
		{
			workingMap = (Hashtable<String,String>)parameterMap.clone();
			canonicalWordCount=0; 
			wordsPresentCount=0;
			extraWords=0;
			consistentWorld = StandardTools.parseToKeyValueMap(world);
			functionName=consistentWorld.get(functionSetKeyName);
			requiresArgumentsP= consistentWorld.containsKey(parametersRequiredP);
			functionArguments = new LinkedList<String>();
			// Get the hashmap of word substitutions
			substitutionMap = getSubstitutionMap(functionName);
			// apply substitutions to original map
			for (String baseWord:substitutionMap.keySet())
			{
				if (workingMap.containsKey(baseWord))
				{
					workingMap.remove(baseWord);
					if (!workingMap.containsKey(newWord=substitutionMap.get(baseWord)))
					{
						workingMap.put(newWord, wordValueToken);
					}
				}
					
			}
			
			// Get the fraction of words present that are required
			for (String requiredName:consistentWorld.keySet())
			{
				if (consistentWorld.get(requiredName).equals(wordValueToken))
				{
					canonicalWordCount++;
					if (workingMap.containsKey(requiredName))
						wordsPresentCount++;
					
				}
			}
			
			// Get the extra words that aren't in this world
			for (String wordSpoken:workingMap.keySet())
			{
				if (workingMap.get(wordSpoken).equals(wordValueToken))
				{
					if (!consistentWorld.containsKey(wordSpoken))
					{
						if (requiresArgumentsP)
							functionArguments.add(wordSpoken);
						else		
							extraWords++;
					}
				}
			}
			
			// n(E * S)/n(E) <-- if parameters
			// n(E * S)/n(E)*n(E)/(n(E)+n(S-E)) = n(E * S)/n(E + S)
			currentFraction=wordsPresentCount/canonicalWordCount*((requiresArgumentsP)?1:canonicalWordCount/(extraWords+canonicalWordCount));
			if ((currentFraction>maxFraction)||(first))
			{
				first=false;
				maxFraction=currentFraction;
				applicableFunctions = new Hashtable<String, SpeechProcessor.SpeechResults>();
				applicableFunctions.put(functionName, new SpeechProcessor.SpeechResults(functionName,(functionArguments.size()>0)?functionArguments.toArray(new String[0]):null,rawSpeech));
			}
			else
				if (Math.abs(currentFraction-maxFraction)<tolerance)
				{
					applicableFunctions.put(functionName, new SpeechProcessor.SpeechResults(functionName,(functionArguments.size()>0)?functionArguments.toArray(new String[0]):null,rawSpeech));
				}
			
		}
		
		if (applicableFunctions.size()>0)
			return applicableFunctions.values().toArray(new SpeechProcessor.SpeechResults[0]);
		else
			return null;
		
	}
	
	
	private Hashtable<String, String> getSubstitutionMap(String functionName)
	{
		Hashtable<String, String> replacementMap = new Hashtable<String, String>(), argumentSet = new Hashtable<String, String>();
		argumentSet.put(functionSetKeyName, functionName);
		argumentSet.put(kvSubstitutionOnlyFilter.GetKey(), kvSubstitutionOnlyFilter.GetValue());
		String[] worlds=j_Controller.getAllConsistentWorlds(argumentSet);
		Hashtable<String,String> resultSet;
		
		for (String world:worlds)
		{
			resultSet=StandardTools.parseToKeyValueMap(world);
			if (resultSet.containsKey(spokenWordKeyName))
			{
				replacementMap.put(resultSet.get(spokenWordKeyName), resultSet.get(substitutedWordKeyName));
			}
		}
		return replacementMap;
	}
	
	
}
